`timescale 1ns / 1ps
`include "SimCtrl.h"
`default_nettype none
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2020/06/29 16:59:53
// Design Name: 
// Module Name: SRAM_Ctrl_Unit
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module Bridge(
    input   wire    clk_50M,
    input   wire    clk,
    input   wire    clr,
    inout   wire    [31:0] base_ram_data,  //BaseRAM数据，低8位与CPLD串口控制器共享
    output  wire    [19:0] base_ram_addr, //BaseRAM地址
    output  wire    [3:0] base_ram_be_n,  //BaseRAM字节使能，低有效。如果不使用字节使能，请保持为0
    output  wire    base_ram_ce_n,       //BaseRAM片选，低有效
    output  wire    base_ram_oe_n,       //BaseRAM读使能，低有效
    output  wire    base_ram_we_n,       //BaseRAM写使能，低有效
    //ExtRAM信号
    inout   wire    [31:0] ext_ram_data,  //ExtRAM数据
    output  wire    [19:0] ext_ram_addr, //ExtRAM地址
    output  wire    [3:0] ext_ram_be_n,  //ExtRAM字节使能，低有效。如果不使用字节使能，请保持为0
    output  wire    ext_ram_ce_n,       //ExtRAM片选，低有效
    output  wire    ext_ram_oe_n,       //ExtRAM读使能，低有效
    output  wire    ext_ram_we_n,       //ExtRAM写使能，低有效
    ///////////////
    input   wire    [31:0] I_sram_addr,
    output	wire    [31:0] I_sram_data,
	output	wire    I_sram_busy,//与M级的访问出现冲突

    input   wire    [31:0]  E_Mem_addr,
    input   wire    [31:0]  E_Mem_write_data,
    output  wire    [31:0]  E_Mem_read_data,
    input	wire    [3:0]   E_MemBitEnable,
	input   wire    E_MemReadEnable,
    input   wire    E_MemWriteEnable,
    ////////////////
    output wire txd,  //直连串口发送端
    input  wire rxd,  //直连串口接收端

    output  wire    [31:0] UART_DATA_out,
    output  wire    [31:0] UART_STATUS_out
    );


    
// #     0x80000000～0x803FFFFF映射到BaseRAM；
// #     0x80400000～0x807FFFFF映射到ExtRAM。
    ////////////////////////////////////////////////////////////////////////////////
    parameter   BASEMEM_BASE = 32'h8000_0000;
    parameter   BASEMEM_TOP  = 32'h803F_FFFF;
    wire    E_using_Base_Sram ;
    reg     E_using_Base_Sram_r;
    reg     E_using_Base_Sram_r2;
    reg     E_MemWriteEnable_r;
    wire [31:0] E_Base_data;
    reg [31:0] E_Mem_write_data_r;

    wire    [31:0] base_ram_vaddr;
    wire    I_Mem_addr_in_base;
    wire    E_Mem_addr_in_base;

    always @ (posedge clk)begin
        E_MemWriteEnable_r  <=  E_MemWriteEnable;
        E_Mem_write_data_r  <= E_Mem_write_data;
        E_using_Base_Sram_r <= E_using_Base_Sram; 
        E_using_Base_Sram_r2<=E_using_Base_Sram_r;
    end

    assign  I_Mem_addr_in_base = (BASEMEM_BASE<=I_sram_addr && I_sram_addr <=BASEMEM_TOP);
    assign  E_Mem_addr_in_base = (BASEMEM_BASE<=E_Mem_addr  && E_Mem_addr  <=BASEMEM_TOP);
    assign  E_using_Base_Sram = ( E_MemReadEnable|E_MemWriteEnable) &E_Mem_addr_in_base;
    assign  base_ram_vaddr  = (E_using_Base_Sram  ?   E_Mem_addr  :   I_sram_addr) - BASEMEM_BASE;//区分不同的地址

    assign  base_ram_addr = {3'b000,3'b00,base_ram_vaddr[28:2]};
    assign  base_ram_data = (E_MemWriteEnable &E_using_Base_Sram)?   E_Mem_write_data  :  {32{1'bz}};
    assign  base_ram_be_n = ~(E_using_Base_Sram    ?   E_MemBitEnable:4'b1111);//E使用的时候，按照字节使能来进行。否则，全部有效。同时记得要取反。
    assign  base_ram_ce_n = 0;//始终片选中BaseRAM
    assign  base_ram_oe_n = (E_MemWriteEnable&E_using_Base_Sram);//|(E_MemWriteEnable_r&E_using_Base_Sram_r);//Mem在写的时候禁止读,否则一直读
    assign  base_ram_we_n = ~(E_MemWriteEnable&E_using_Base_Sram);//判断是否在写

    `ifdef BASE_RAM_ECHO
        always @ (posedge clk) 
            if(~base_ram_we_n)
                $display("Writing %x to Base:%x vaddr:%x",E_Mem_write_data,base_ram_addr,E_Mem_addr);
    `endif
    //////////////////////////////////////////////////////////////////////////////////
    parameter   EXTMEM_BASE = 32'h8040_0000;
    parameter   EXTMEM_TOP  = 32'h807F_FFFF;
    wire    I_Mem_addr_in_ext;
    wire    E_Mem_addr_in_ext;
    wire    E_using_Ext_Sram;
    reg     E_using_Ext_Sram_r;
    reg     E_using_Ext_Sram_r2;
    wire [31:0] ext_ram_vaddr;
    always @ (posedge clk)begin
        E_using_Ext_Sram_r <= E_using_Ext_Sram; 
        E_using_Ext_Sram_r2<= E_using_Ext_Sram_r;
    end

    assign  I_Mem_addr_in_ext = (EXTMEM_BASE<=I_sram_addr && I_sram_addr <=EXTMEM_TOP);
    assign  E_Mem_addr_in_ext = (EXTMEM_BASE<=E_Mem_addr  && E_Mem_addr  <=EXTMEM_TOP);
    assign  E_using_Ext_Sram = ( E_MemReadEnable|E_MemWriteEnable)&E_Mem_addr_in_ext;
    assign  ext_ram_vaddr = (E_using_Ext_Sram    ?   E_Mem_addr : I_sram_addr)-EXTMEM_BASE;

    assign  ext_ram_addr  = {3'b000,3'b00,ext_ram_vaddr[28:2]};
    assign  ext_ram_data = E_MemWriteEnable ?   E_Mem_write_data    :   {32{1'bz}};
    assign  ext_ram_be_n = ~(E_using_Ext_Sram?E_MemBitEnable:4'b1111);//只有E才会用
    assign  ext_ram_ce_n = 0;//始终片选中ExtRAM
    assign  ext_ram_oe_n = E_MemWriteEnable&E_using_Ext_Sram;//Mem在写的时候禁止读,否则一直读
    assign  ext_ram_we_n = ~(E_MemWriteEnable&E_using_Ext_Sram);//判断是否在写
    `ifdef EXT_RAM_ECHO
    always @ (posedge clk) begin
        if(~ext_ram_we_n)
            $display("Writing %x to Ext:%x",E_Mem_write_data,ext_ram_addr);
    end
    `endif

    //////////////////////////////////////////////////////////////////////////////////
    assign  I_sram_busy = ((I_Mem_addr_in_base) & (E_using_Base_Sram|E_using_Base_Sram_r|E_using_Base_Sram_r2))
                            || (I_Mem_addr_in_ext) & (E_using_Ext_Sram|E_using_Ext_Sram_r|E_using_Ext_Sram_r2);//Mem级的优先级更高

    //////////////////////////////////////////////////////////////////////////////////

    // 0xBFD003F8 数据收发接口
    //0xBFD003FC [1]:recived [0]:IDLE  
    parameter UART_DATA_ADDR = 32'hBFD003F8;
    parameter UART_STATUS_ADDR = 32'hBFD003FC;

    parameter ClkFrequency = 50000000;// 50MHz
	parameter Baud = 9600;

    wire TxD_valid;
    wire TxD_ready;
    wire [7:0]  TxD_din;

    wire RxD_valid;
    wire RxD_ready;
    wire [7:0]  RxD_dout;

    wire [31:0] UART_DATA;
    wire [31:0] UART_STATUS;


    assign TxD_valid = (E_Mem_addr == UART_DATA_ADDR && E_MemWriteEnable && E_MemBitEnable[0]);
    assign TxD_din = E_Mem_write_data[7:0];
    assign RxD_ready = (E_Mem_addr == UART_DATA_ADDR && E_MemReadEnable  && E_MemBitEnable[0]);
    assign UART_DATA = {24'b0,RxD_dout};
    assign UART_STATUS = {30'b0,RxD_valid,TxD_ready};
    UART_Unit UART_Unit(
        .clk_50M(clk_50M),
        .clk(clk),
        .clr(clr),
        .rxd(rxd),
        .txd(txd),
        .TxD_valid(TxD_valid),
        .TxD_ready(TxD_ready),
        .TxD_din(TxD_din),
        .RxD_valid(RxD_valid),
        .RxD_ready(RxD_ready),
        .RxD_dout(RxD_dout)
    );

    //分发不同的数据
    assign I_sram_data = base_ram_data;
    wire [31:0] E_Mem_read_data_raw  =  E_Mem_addr == UART_DATA_ADDR   ?   UART_DATA://UART要用打一拍的地址
                                        E_Mem_addr == UART_STATUS_ADDR? UART_STATUS:
                                        (32'h8040_0000<=E_Mem_addr && E_Mem_addr <=32'h807F_FFFF)    ?   ext_ram_data:
                                        base_ram_data;
    assign  E_Mem_read_data = {{8{E_MemBitEnable[3]}},{8{E_MemBitEnable[2]}},{8{E_MemBitEnable[1]}},{8{E_MemBitEnable[0]}}} & E_Mem_read_data_raw;

    assign UART_DATA_out = UART_DATA;
    assign UART_STATUS_out = UART_STATUS;

endmodule
